#include "Common.h"
#include "Skeleton.h"
#include "Entity.h"

SkeletonInstance::SkeletonInstance(Entity* parent, const Skeleton* skeleton)
	: mParent(parent)
	, mSkeleton(skeleton)
	, mBoneInstances(skeleton->Bones)
	, mAllAnimations(skeleton->Animations)
{
	mBoneMatrices.Resize(mBoneInstances.Size(), Matrix::Identity);
}

SkeletonInstance::~SkeletonInstance()
{
}

void SkeletonInstance::Update(float elapsedTime)
{
	bool animationDirty = mAllAnimations.Update(elapsedTime);
	if (animationDirty)
		UpdateAnimation();
}

void SkeletonInstance::UpdateAnimation()
{
	// reset all of the bones.
	mBoneInstances.ResetBones();

	// apply animation.
	const AnimationStateSet& enabledAnims = mAllAnimations.getEnabledAnimations();
	for (AnimationStateSet::const_iterator it(enabledAnims.begin()), end(enabledAnims.end()); it != end; it++)
	{
		const AnimationState* animState = *it;
		const Animation* animation = animState->Anim;
		const AnimationTrackVector& tracks = animation->Tracks;
		const float timePosition = animState->TimePosition;
		const float weight = animState->Weight;

		for (AnimationTrackVector::const_iterator trackIt(tracks.begin()), trackEnd(tracks.end()); trackIt != trackEnd; trackIt++)
		{
			const AnimationTrack& track = *trackIt;
			if (track.KeyFrames.empty() || track.BoneIndex >= mBoneInstances.Size())
				continue;
			
			KeyFrame keyFrame;
			track.Interprete(timePosition, keyFrame);

			BoneInstance& boneInstance = mBoneInstances.Get(track.BoneIndex);
			boneInstance.Translate += keyFrame.Translate * weight;
			boneInstance.Orientation *= LerpQuat(Quaternion::Identity, keyFrame.Orientation, weight);// * boneInstance.Orientation;
			if (keyFrame.Scale != Vector3::One)
				boneInstance.Scale *= keyFrame.Scale;
			boneInstance.NeedUpdate = true;
		}
	}

	// update derive transform.
	mBoneInstances.UpdateTransform();

	// fetch the bone matrix out.
	mBoneInstances.GetBoneMatrices(&mBoneMatrices.Get(0));
}

bool SkeletonInstance::EnableAnim(const std::string& name, bool loop)
{
	return mAllAnimations.EnableAnim(name, loop);
}
